home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
make5.cq
/
MAKE.C
Wrap
Text File
|
1985-06-03
|
25KB
|
831 lines
/*
This a called 'Make' and is a much simplified version of
the make utility on UNIX (a trademark or something of AT&T)
written using the Lattice C compile
for the IBM Personal Computer. The Lattice package is
available from Lifeboat Assoc. 1651 Third Avenue
New York, NY 10128 .
'Make' takes a file of dependencies (a 'makefile') and
decides what commands have to be executed to bring the files
up to date. These commands are either executed directly from
'Make' or written to the standard output without executing
them.
'Makefile' format:
- There must be a 'makefile'; you can't take input from the
standard input.
- The default name of the 'makefile' is 'MAKEFILE' on the
default disk. Different 'makefiles' can be specified using
the '-f' option on the command line. If the '-f' option is
used, the default 'makefile' is not processed.
- Any blank lines in the 'makefile(s)' are ignored.
- A line in a 'makefile' that starts with a tab character is
a 'howto' line and consists of a command name followed by
arguments. The command name must be a file name, e.g.
'cc'. When commands are executed, the PATH environment
variable is used to find the command, in (hopefully) the
same manner as DOS does. 'Howto' lines apply to the most
recently preceding 'dependency' line. It is an error for
a 'howto' line to precede the first 'dependency' line.
- Any other non-blank line is a 'dependency' line. 'Dependency'
lines consist of a filename followed by a (possibly empty) list
of dependent filenames.
Operation:
Syntax:
make [filename] [-f makefilename] [-i] [-n]
-i means continue even if an error is encountered while
executing a command.
-n means don't execute the commands, just write the ones that
should be executed to the standard output. This is useful
for creating batch files, for example.
-f specifies that the following argument is the name of a makefile
to be used instead of the default (MAKEFILE).
All arguments may be repeated and relative position of the
arguments is not important. If multiple definitions of a file
are found, only the first one is significant.
First, 'Make' reads all of the makefiles. It then proceeds through
all of the filename arguments, 'making' each one in turn. A file
is remade if it is out of date with respect to the files it depends
on or is non-existent. Dependencies are processed in a 'tree' fashion,
so that the lowest-order files are remade first.
'Make' cannot execute DOS built-in commands e.g. 'cd' or 'dir'.
'Make' uses the first 20k or so after the resident portion of DOS.
all definitions and howto's are stored in dynamically allocated struct's.
Any executed commands are loaded above 'Make' in memory.
'Make' REQUIRES DOS 2.0 (or higher?).
The code is a little kludgy in places.
No guarantees or warranties of any kind: I think it works and
I use it.
Any suggestions for improvements gratefully accepted.
I believe that commercial versions exist. I also beleive that they
would be superior to this.
version 2.0 comments:
This program was converted to Lattice 'C' ver 2.11 on 15 jun 84.
This allowed the use of the lattice 'fork' command. The command
will automatically search the path name specified to find the
desired executable image. This also allows the use of image names
with out the extension. ie 'lc1' instead of 'lc1.exe'. All of
the assembler routines have been replaced with lattice dos calls.
The Lattice version uses about 55k bytes less memory than the
Desmet version. This is nice for the systems with already tight
memory requirements.
version 3 comments:
The default makefile name is MAKEFILE not MAKEFILE.DAT.
There now is a symbol processor to do substitiutions
in the argument line.
A symbol definition MUST begin with a $.
An example follows.
Fixed a bug-If a dependent file did not exist then make didn't
work correctly.
Checks to see if a command results in a non-zero return code.
If so then aborts unless the -i flag is used.
Any comments on this code should be directed to
Jeffrey Spidle
Systems Analyst
Office of Continuing Education
Iowa State University
Ames, IA 50011
or a message on one of the following BBS.
Gene Plantz (312)887-4227
Lynn Long (918)749-0718
Bob Blackwell (319)363-3314
*/
/*
Written by John M Sellens, April, 1984
Modified for Lattice C ver 2.11 by Jeff Spidle jun 15 84
Code is all original except where indicated otherwise.
Until August, 1984:
jmsellens@watrose.UUCP
107 - 180 Brybeck Cres.
Kitchener, Ontario
N2M 5G4
After August, 1984:
c/o 1135 Lansdowne Ave. SW
Calgary, Alberta
T2S 1A4
(c) Copyright 1984 John M Sellens
Permission is granted to use, distribute and/or modify this code unless
done for direct commercial profit. If you find these routines useful,
modest contributions (monetary or otherwise) will be gratefully accepted.
Author's name, address and this notice must be included in any copies.
<TAB> = ASCII 09
An example: To compile this program the following makefile was used
$CFLAGS -ms -i/code/c/lc/
make.exe make.obj
<TAB>link /code/c/lc/s/cs+make,make,make,/code/c/lc/s/lcs -map
make.obj make.c /code/c/lc/stdio.h
<TAB>lc1 make $CFLAGS -i/code/c/lc/s/ -n
<TAB>lc2 make
An explination: make.exe is a dependent file. Is is dependent on
make.obj. make.obj is dependent on make.c and stdio.h. If the
following command is issued:MAKE make.exe then make will
check to see if either make.c or stdio.h has a newer date&time
than make.obj. if so then the 2 compile instructions are issued.
then the link instruction will be issued. If only make.obj is
newer than make.exe then only the link step would be executed.
The symbol substitution will end up having the lc1 call look like
lc1 make -ms -i/code/c/lc/ -i/code/c/lc/s/ -n
Hints: Dependencies can be in any order. Make will resolve them
correctly.
How to lines must begin with a <TAB> not just 7 spaces.
Symbol definition lines must start with a $.
Symbols cannot have other symbols in their definition.
A symbol may have a max of 39 characters.
The equate for a symbol may be up to 80 characters.
You may have an unlimited(within reason) number of
symbols.
A symbol that is not defined will be copied to the
output line. ie
lc2 $TEST
with $TEST not defined will create the command
lc2 $TEST
Symbols are case specific. upper and lower case are significant.
The command line must specify what file you wish to
make. You may have more than one set of file definitions
in a makefile. If you do you may run out of memory. I
haven't run into this yet but I suppose it is possible.
If a command returns an error-code (ERRORLEVEL) not equal
to zero then MAKE thinks that there was an error. MAKE
will abort processing unless the -i (ignore errors) flag
is used.
Any suggestions or improvements will be much appreciated. I
am next going to try to put definable symbols for substitution
in a makefile next aka UNIX-MAKE. So we will see what happens.
*/
#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#define TRUE 1
#define FALSE 0
#define DEFAULT "MAKEFILE"
#define INMAX 255 /* maximum input line length */
extern char *getmem() ;
extern int _oserr, errno ;
struct sym_ptr
{
struct sym_str *data ;
struct sym_ptr *next ;
} ;
struct sym_str
{
char symbol[40] ; /* max symbol size in lattice c is 39 chars */
char equals[81] ; /* so we had to default to something */
} ;
/* declare some global variables for the symbols */
struct sym_ptr list ;
struct sym_ptr *current ; /* pointer to the current symbol */
/* thus we know where to add more to */
struct howrec {
char *howcom,*howargs;
struct howrec *nexthow;
};
struct deprec {
char *name;
struct defnrec *def;
struct deprec *nextdep;
};
struct defnrec {
char *name;
int uptodate;
long modified;
struct deprec *dependson;
struct howrec *howto;
struct defnrec *nextdefn;
};
struct dorec {
char *name;
struct dorec *nextdo;
};
struct defnrec *defnlist;
struct dorec *dolist;
int execute;
int stopOnErr;
int madesomething;
int knowhow;
main(argc,argv)
int argc;
char *argv[];
{
long make();
long void ;
current = &list ;
current->next = NULL ;
current->data = NULL ;
init(argc,argv);
/* now fall down the dolist and do them all */
while (dolist != NULL) {
madesomething = FALSE;
void = make(dolist->name); /* ignore return value */
if (!madesomething) {
if (knowhow)
fprintf(stderr,"Make: '%s' is up to date\n",dolist->name);
else {
fprintf(stderr,"Make: Don't know how to make '%s'\n",
dolist->name);
if (stopOnErr)
exit(-1);
}
}
dolist = dolist->nextdo;
}
}
init(argc,argv)
int argc;
char *argv[];
{
int i, usedefault;
dolist = NULL;
defnlist = NULL;
usedefault = TRUE;
execute = TRUE;
stopOnErr = TRUE;
for (i=1; i < argc; i++) {
if (argv[i][0] == '-') { /* option */
switch (argv[i][1]) {
case 'f': case 'F': /* arg following is a makefile */
if (++i < argc) {
readmakefile(argv[i]);
usedefault = FALSE;
} else {
fprintf(stderr,"Make: '-f' requires filename\n");
exit(-1);
}
break;
case 'i': case 'I': /* ignore errors on execution */
stopOnErr = FALSE;
break;
case 'n': case 'N': /* don't execute commands - just print */
execute = FALSE;
break;
default:
fprintf(stderr,"Make: unknown option '%s'\n",argv[i]);
}
} else { /* it must be something to make */
add_do(argv[i]);
}
}
if (usedefault)
readmakefile(DEFAULT);
}
long make(s) /* returns the modified date/time */
char *s;
{
struct defnrec *defnp;
struct deprec *depp;
struct howrec *howp;
char exp_args[128] ;
char system_call[255] ;
long latest, getmodified(), lmax(), currtime();
int void, return_code ;
/* look for the definition */
defnp = defnlist;
while (defnp != NULL) {
if (strcmp(defnp->name,s) == 0)
break;
defnp = defnp->nextdefn;
}
if (defnp == NULL) { /* don't know how to make it */
knowhow = FALSE;
latest = getmodified(s);
if (latest==0) { /* doesn't exist but don't know how to make */
fprintf(stderr,"Make: Can't make '%s'\n",s);
exit(-1);
} else /* exists - assume it's up to date since we don't know */
return(latest);
}
if (defnp->uptodate)
return(defnp->modified);
/* now make sure everything that it depends on is up to date */
latest = 0;
depp = defnp->dependson;
while (depp != NULL) {
latest = lmax(make(depp->name),latest);
depp = depp->nextdep;
}
knowhow = TRUE; /* has dependencies therefore we know how */
/* if necessary, execute all of the commands to make it */
/* if (out of date) || (depends on nothing) */
if (latest > defnp->modified || defnp->dependson==NULL) {
/* make those suckers */
howp = defnp->howto;
while (howp != NULL) {
expand_args(howp->howargs, exp_args) ;
printf("%s %s\n",howp->howcom,exp_args);
if (execute)
{
void = forklp(howp->howcom,exp_args,NULL) ;
if (void == 0) /* success loading function */
{
/* now do a wait to see if the function returns an ok code */
return_code = wait() ;
if (return_code != 0) /* error code returned */
{
printf("MAKE: error returned from %s %s, code = %d\n",
howp->howcom, exp_args, return_code ) ;
if (stopOnErr)
exit(-1);
} /* endif return_code != 0 */
}
else
{ /* fork had an error loading */
if (_oserr == 2) /* error for file not found */
{ /* lets do a system call instead then */
strcpy( system_call, howp->howcom ) ;
strcat( system_call, " " ) ;
strcat( system_call, exp_args ) ;
void = system( system_call ) ;
if (void != 0) /* error in system call */
{
printf("MAKE: system call error from %s %s, code = %d\n",
howp->howcom, exp_args, _oserr ) ;
if (stopOnErr)
exit(-1);
} /* endif id void != 0 */
}
else
{
printf("\nMake: error on '%s %s' _oserr = %d\n",
howp->howcom,exp_args, _oserr);
if (stopOnErr)
exit(-1);
} /* endif _oserr == 2 */
} /* endif void == 0 */
} /* endif execute */
howp = howp->nexthow;
} /* end while */
defnp->modified = currtime();
defnp->uptodate = TRUE;
if (defnp->howto != NULL) /* we had instructions */
madesomething = TRUE;
}
return(defnp->modified);
}
expand_args( in, out )
char *in, *out ;
{
char *posin, *posout, *possym ;
char symbol[40] ;
char *get_symval(), *symval ;
posin = in ;
posout = out ;
while (TRUE)
{
while ( (*posin != '$') && (*posin != '\0') )
*posout++ = *posin++ ; /* copy till we find a $ */
if (*posin == '\0') /* have reached the end of the input */
{ /* so exit */
*posout = '\0' ; /* terminate the output string first tho */
return ;
}
possym = symbol ; /* point symbol pointer at the begining */
/* skip over the $ so we can test for alphanumeric */
*possym++ = *posin++ ; /* copy's the $ */
while ( isalnum(*posin) )
*possym++ = *posin++ ; /* copy in the suspected symbol */
*possym = '\0' ; /* zero terminate it */
/* get the value of the found symbol */
if ( (symval = get_symval( symbol )) == NULL )
{ /* do this if there isn't a symbol match */
possym = symbol ; /* reset the symbol position */
/* copy the symbol to the output */
while (*possym != '\0' )
*posout++ = *possym++ ;
}
else /* do this if there is one */
{
/* copy the symbol equate to the output */
while (*symval != 0)
*posout++ = *symval++ ;
}
}
/* should never get to here */
return ;
}
char *get_symval( symbol )
char *symbol;
{
struct sym_ptr *cur_ptr ;
cur_ptr = &list ; /* start at the begining of the list */
while (cur_ptr->data != NULL) /* while there is data */
{
if (strcmp(cur_ptr->data->symbol, symbol) == 0) /* they match */
{
return(cur_ptr->data->equals) ; /* return the pointer to */
/* the equate string */
}
else /* they dont */
cur_ptr = cur_ptr->next ; /* point cur_ptr to the next symbol */
}
return(NULL) ;
}
add_do(s)
char *s;
{
struct dorec *ptr1, *ptr2;
char *get_mem();
ptr1 = (struct dorec *)get_mem(sizeof(struct dorec));
ptr1->name = s; /* okay since only called with an argv */
ptr1->nextdo = NULL;
uppercase(ptr1->name);
/* now go down the dolist */
if (dolist == NULL)
dolist = ptr1;
else {
ptr2 = dolist;
while (ptr2->nextdo != NULL)
ptr2 = ptr2->nextdo;
ptr2->nextdo = ptr1;
}
}
readmakefile(s)
char *s;
{
int doneline, pos, i, j;
long getmodified() ;
FILE *fil ;
char inline[INMAX], info[INMAX];
char *get_mem();
struct defnrec *defnp, *defnp2;
struct deprec *depp, *depp2;
struct howrec *howp, *howp2;
if ( (fil = fopen(s,"r")) == NULL)
{
fprintf(stderr,"Make: Couldn't open '%s'\n",s);
return;
}
while (fgets(inline,INMAX,fil) != NULL)
{
inline[strlen(inline)-1] = '\0'; /* strip trailing newline */
if (inline[0] == '\0') /* ignore blank lines */
continue;
switch (inline[0])
{
default:
uppercase(inline);
/* get what we're defining into info */
if (sscanf(inline,"%s ",info) != 1)
{
fprintf(stderr,"Make: Can't scan: '%s'\n",inline);
continue;
}
/* get a new struct */
defnp = (struct defnrec *)get_mem(sizeof(struct defnrec));
/* add it to the end of defnlist */
if (defnlist == NULL)
defnlist = defnp;
else
{
defnp2 = defnlist;
while (defnp2->nextdefn != NULL)
defnp2 = defnp2->nextdefn;
defnp2->nextdefn = defnp;
}
/* initialize it */
defnp->name = get_mem(strlen(info)+1);
strcpy(defnp->name,info);
defnp->uptodate = FALSE; /* actually unknown */
defnp->modified = getmodified(defnp->name);
defnp->dependson = NULL;
defnp->howto = NULL;
defnp->nextdefn = NULL;
/* now go through all of its dependecies */
/* first move past the first name */
pos = 0;
while (isspace(inline[pos]))
pos++;
while (!isspace(inline[pos]) && inline[pos]!='\0')
pos++;
/* now loop through those suckers */
doneline = FALSE;
while (!doneline)
{
while (isspace(inline[pos]))
pos++;
if (inline[pos] == '\0')
{
doneline = TRUE;
continue;
}
for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0'; )
info[i++] = inline[pos++];
info[i] = '\0';
/* get a new struct */
depp = (struct deprec *)get_mem(sizeof(struct deprec));
/* add it to the end of deplist */
if (defnp->dependson == NULL)
defnp->dependson = depp;
else
{
depp2 = defnp->dependson;
while (depp2->nextdep != NULL)
depp2 = depp2->nextdep;
depp2->nextdep = depp;
}
depp->name = get_mem(strlen(info)+1);
strcpy(depp->name,info);
depp->nextdep = NULL;
}
break ;
case '+': /* must be a continuation line */
uppercase(inline);
/* now go through all of its dependecies */
/* first move past the + sign */
pos = 1;
/* now loop through those suckers */
doneline = FALSE;
while (!doneline)
{
while (isspace(inline[pos]))
pos++;
if (inline[pos] == '\0')
{
doneline = TRUE;
continue;
}
for(i = 0; !isspace(inline[pos]) && inline[pos]!='\0'; )
info[i++] = inline[pos++];
info[i] = '\0';
/* get a new struct */
depp = (struct deprec *)get_mem(sizeof(struct deprec));
/* add it to the end of deplist */
if (defnp->dependson == NULL)
defnp->dependson = depp;
else
{
depp2 = defnp->dependson;
while (depp2->nextdep != NULL)
depp2 = depp2->nextdep;
depp2->nextdep = depp;
}
depp->name = get_mem(strlen(info)+1);
strcpy(depp->name,info);
depp->nextdep = NULL;
}
break ;
case '$': /* must be a symbol definition */
/* now split the line up into symbol and args */
for (pos=0;isspace(inline[pos]); pos++);
;
for (i=pos; !isspace(inline[i]) && inline[i]!='\0'; i++)
;
/* if there is something there, allocate mem and copy */
if (i != pos)
{
/* get a new struct */
current->data = (struct sym_str *)get_mem(sizeof(struct sym_str));
current->next = (struct sym_ptr *)get_mem(sizeof(struct sym_ptr));
for(j=0; pos < i; )
current->data->symbol[j++] = inline[pos++] ;
current->data->symbol[j] = '\0';
/* now look for any argumentative part */
while (isspace(inline[pos]))
pos++;
for(i=0; inline[pos] != '\0'; )
current->data->equals[i++] = inline[pos++] ;
current->data->equals[i] = '\0' ;
current = current->next ;
current->next = NULL ;
current->data = NULL ;
}
break ;
case '\t':
if (defnp == NULL)
{
fprintf(stderr,"Make: Howto line without a definition\n");
fprintf(stderr,"Make: '%s'\n",inline);
}
/* now split the line up into command and args */
for (pos=0;isspace(inline[pos]); pos++);
;
for (i=pos; !isspace(inline[i]) && inline[i]!='\0'; i++)
;
/* if there is something there, allocate mem and copy */
if (i != pos)
{
/* get a new struct */
howp = (struct howrec *)get_mem(sizeof(struct howrec));
/* add it to the end of howlist */
if (defnp->howto == NULL)
defnp->howto = howp;
else
{
howp2 = defnp->howto;
while (howp2->nexthow != NULL)
howp2 = howp2->nexthow;
howp2->nexthow = howp;
}
/* copy command filename */
howp->howcom = get_mem(i-pos+1);
for(j=0; pos < i; )
howp->howcom[j++] = inline[pos++];
howp->howcom[j] = '\0';
/* now look for any argumentative part */
while (isspace(inline[pos]))
pos++;
howp->howargs = get_mem(strlen(inline)-pos + 1);
for(i=0; inline[pos] != '\0'; )
howp->howargs[i++] = inline[pos++];
howp->howargs[i] = '\0';
howp->nexthow = NULL;
} /* if */
break ;
} /* switch */
} /* while */
fclose( fil ) ;
} /* readmakefile */
uppercase(s)
char *s;
{
for( ; *s != '\0'; s++)
*s = toupper(*s);
}
char *get_mem(size) /* different name to differentiate it */
int size; /* from lattice C 2.11 function */
{
char *p;
if ((p = getmem(size)) == NULL) {
fprintf(stderr,"Make: Ran out of memory...\n");
exit(-1);
}
return(p);
}
long getmodified(name)
char *name;
{
struct dt_tm {
int time ;
int date ;
} ;
union vals {
long ret_dt ;
struct dt_tm dt ;
} out_val ;
union REGS in_regs ;
union REGS out_regs ;
union FLAGS ret_flags ;
int file_handle ;
/* get the file handle */
in_regs.x.dx = (int)name ;
in_regs.h.al = 0 ;
in_regs.h.ah = 0x3d ;
ret_flags.all_flags = intdos( &in_regs, &out_regs ) ;
file_handle = out_regs.x.ax ;
/* if the file doesn't exist then return 0 for date&time */
if ((ret_flags.flags.cf == 1) && ((file_handle == 2) ||
(file_handle == 4) ||
(file_handle == 5) ||
(file_handle == 12)))
{
return( 0 ) ;
}
/* get the date */
in_regs.x.bx = file_handle ;
in_regs.h.al = 0 ;
in_regs.h.ah = 0x57 ;
intdos( &in_regs, &out_regs ) ;
out_val.dt.date = out_regs.x.dx ;
out_val.dt.time = out_regs.x.cx ;
/* close out the file */
in_regs.x.bx = file_handle ;
in_regs.h.ah = 0x3e ;
intdos( &in_regs, &out_regs ) ;
return( out_val.ret_dt ) ;
}
long currtime()
/* return a long encoding the current date and time */
{
union {
long ret_dt ;
int dt[2] ;
} out_val ;
union REGS in_regs ;
union REGS out_regs ;
in_regs.h.al = 0 ;
in_regs.h.ah = 0x2a ;
intdos( &in_regs, &out_regs ) ;
out_regs.x.cx -= 1980 ;
out_val.dt[1] = (out_regs.x.cx << 9) ;
out_val.dt[1] |= (out_regs.h.dh << 5) ;
out_val.dt[1] |= (out_regs.h.dl ) ;
in_regs.h.al = 0 ;
in_regs.h.ah = 0x2c ;
intdos( &in_regs, &out_regs ) ;
out_val.dt[0] = (out_regs.h.ch << 11) ;
out_val.dt[0] |= (out_regs.h.cl << 5) ;
out_val.dt[0] |= (out_regs.h.dh >> 1) ;
return( out_val.ret_dt ) ;
}
long lmax(a,b)
long a,b;
{
return(a>b ? a : b);
}
/* ---------- */